home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1997 / HAM Radio 1997.iso / vcls / lexscan / lexscan.pas < prev    next >
Pascal/Delphi Source File  |  1996-04-08  |  9KB  |  334 lines

  1. ========
  2. Newsgroups: comp.lang.pascal.delphi.components
  3. Subject: Lexical Scanner [4/4]
  4. From: jbui@scd.hp.com (Joseph Bui)
  5. Date: 27 Jul 1995 17:00:17 GMT
  6.  
  7. {
  8.   ************************ LEXSCAN.PAS ************************
  9. }
  10. unit Lexscan;
  11.  
  12. interface
  13.  
  14. uses
  15.   TypInfo, Classes, SysUtils, StrUtils;
  16.  
  17. type
  18.   TCustomScanner = class(TObject)
  19.   private
  20.     FToken: char;
  21.     FTokenString: string;
  22.     FPosition, FLine: longint;
  23.     FStream: TStream;
  24.     procedure SetLine(Value: longint);
  25.     procedure SetPosition(Value: longint);
  26.     function GetTokenFloat: extended;
  27.     function GetTokenInt: longint;
  28.   protected
  29.     property Stream: TStream read FStream write FStream;
  30.   public
  31.     property Token: char read FToken;
  32.     property TokenString: string read FTokenString;
  33.     property TokenFloat: extended read GetTokenFloat;
  34.     property TokenInt: longint read GetTokenInt;
  35.     property Position: longint read FPosition write SetPosition;
  36.     property Line: longint read FLine write SetLine;
  37.     function NextToken: char;
  38.     function LastToken: char;
  39.     function LineString: string;
  40.     constructor Create;
  41.   end;
  42.  
  43.   TFileScanner = class(TCustomScanner)
  44.   private
  45.     FFileName: string;
  46.   public
  47.     property FileName: string read FFileName;
  48.     constructor Create(AFileName: string);
  49.     destructor Destroy;
  50.   end;
  51.  
  52.   TStreamScanner = class(TCustomScanner)
  53.   public
  54.     constructor Create(AStream: TStream);
  55.   end;
  56.  
  57. const
  58. {
  59.   *************************************************************
  60.  
  61.   Change these constants to customize how the scanner behaves.
  62.   Because of case statements, I did not make these fields of
  63.   the TCustomScanner object as fields.
  64.  
  65.   *************************************************************
  66. }
  67.   NewLineDelimiter = #10; {line feed}
  68.   EofToken = #0; {End of File token}
  69.   IdentifierToken = #1;
  70.   StringToken = #2;
  71.   IntegerToken = #3;
  72.   FloatToken = #4;
  73.   BlackSpaces: TChars = [#33..#126];
  74.   Identifiers: TChars = [#48..#57, #65..#90, #97..#122]; {SetAlphas SetDigits}
  75.   IdentifierSymbols: TChars = [#65..#90, #95, #97..#122]; {SetAlphas, '_'}
  76.   Tokens: TChars = [#33..#47, #58..#64, #91..#94, #96, #123..#126]; {SetBlackSpaces !SetIdentifiers}
  77.   {NewLineDelimiter MUST be in WhiteSpaces}
  78.   WhiteSpaces: TChars = [#0..#32, #127];
  79.  
  80. {
  81.   These constants are for identifying pascal numbers. Changing these values
  82.   will cause TokenInt and TokenFloat to raise EConvertErrors.
  83. }
  84.   StringDelimiter = #39; {''''}
  85.   HexDelimiter = #36; {'$'}
  86.   DecimalDelimiter = '.'; {Can't put in DecimalSeparator...}
  87.   ExponentDelimiter1 = #69; {'E'}
  88.   ExponentDelimiter2 = #101; {'e'}
  89.   PositiveDelimiter = #43; {'+'}
  90.   NegativeDelimiter = #45; {'-'}
  91.   SetAlphas: TChars = [#65..#90, #95, #97..#122]; {'A'..'Z', 'a'..'z'}
  92.   SetDigits: TChars = [#48..#57]; {'0'..'9'}
  93.   SetHexDigits: TChars = [#48..#57, #65..#70, #97..#102]; {SetDigits, 'A'..'F', 'a'..'f'}
  94.   SetNumbers: TChars = [HexDelimiter, PositiveDelimiter, NegativeDelimiter,
  95.       DecimalDelimiter, #48..#57, #65..#70, #97..#102]; {SetHexDigits, '+', '-', '.', '$'}
  96.  
  97. implementation
  98.  
  99. {
  100.   TCustomScanner ***********************************************
  101. }
  102. constructor TCustomScanner.Create;
  103. begin
  104.   inherited Create;
  105.   FToken:=EofToken;
  106.   FTokenString:=Null;
  107.   FPosition:=0;
  108.   FLine:=0;
  109. end;
  110.  
  111. procedure TCustomScanner.SetLine(Value: longint);
  112. var
  113.   Buffer: array[0..255] of char;
  114.   APChar: PChar;
  115. begin
  116.   APChar:=nil;
  117.   if Value < 0 then Value:=0;
  118.   if Value <= FLine then
  119.   begin
  120.     FStream.Seek(0, 0);
  121.     FLine:=0;
  122.   end;
  123.   while (FLine <> Value) and (FStream.Position < FStream.Size) do
  124.   begin
  125.     Buffer[FStream.Read(Buffer, 255)]:=#0;
  126.     APChar:=@Buffer;
  127.     repeat
  128.       APChar:=StrScan(APChar, NewLineDelimiter);
  129.       if APChar <> nil then
  130.       begin
  131.         Inc(FLine);
  132.         Inc(APChar);
  133.       end;
  134.     until (FLine = Value) or (APChar = nil);
  135.   end;
  136.   if APChar <> nil then
  137.     FStream.Seek(-StrLen(APChar), 1);
  138.   NextToken;
  139. end;
  140.  
  141. procedure TCustomScanner.SetPosition(Value: longint);
  142. begin
  143.   if Value >= FStream.Size then
  144.   begin
  145.     FStream.Seek(0,2);
  146.     NextToken;
  147.     exit;
  148.   end;
  149.   if Value < 0 then
  150.     Value:=0;
  151.   Line:=0;
  152.   repeat
  153.     Line:=FLine + 1;
  154.   until FStream.Position >= Value;
  155.   repeat
  156.     LastToken;
  157.   until FPosition <= Value;
  158. end;
  159.  
  160. function TCustomScanner.NextToken: char;
  161. var
  162.   AChar: char;
  163.   Done: boolean;
  164. begin
  165.   FTokenString:=Null;
  166.   FToken:=#0;
  167.   repeat
  168.     Done:=Stream.Read(AChar, 1) = 0;
  169.     if (AChar = NewLineDelimiter) then
  170.       Inc(FLine);
  171.   until not (AChar in WhiteSpaces) or Done;
  172.   if Done then
  173.   begin
  174.     FPosition:=Stream.Size;
  175.     FToken:=EofToken;
  176.     FTokenString:=Null;
  177.   end
  178.   else
  179.   begin
  180.     FPosition:=Stream.Position - 1;
  181.     if (AChar in IdentifierSymbols) then
  182.     begin
  183.       FToken:=IdentifierToken;
  184.       repeat
  185.         AppendStr(FTokenString, AChar);
  186.         Done:=Stream.Read(AChar, 1) = 0;
  187.       until not (AChar in Identifiers) or Done;
  188.       Stream.Seek(FPosition + Length(FTokenString), 0);
  189.     end
  190.     else
  191.     begin
  192.       case AChar of
  193.         StringDelimiter :
  194.         begin
  195.           FToken:=StringToken;
  196.           Done:=Stream.Read(AChar, 1) = 0;
  197.           while not Done and (AChar <> StringDelimiter) do
  198.           begin
  199.             AppendStr(FTokenString, AChar);
  200.             Stream.Read(AChar, 1);
  201.           end;
  202.         end;
  203.         '$', '+', DecimalDelimiter, '-', '0'..'9' : {SetNumberSymbols, DO NOT CHANGE}
  204.         begin
  205.           FToken:=AChar;
  206.           AppendStr(FTokenString, AChar);
  207.           repeat
  208.             Done:=Stream.Read(AChar, 1) = 0;
  209.             AppendStr(FTokenString, AChar);
  210.           until not (AChar in SetNumbers) or Done;
  211.           repeat
  212.             FTokenString[0]:=Chr(Length(FTokenString) - 1);
  213.             if IsAnInt(FTokenString) then
  214.               FToken:=IntegerToken
  215.             else
  216.               if IsAFloat(TokenString) then
  217.                 FToken:=FloatToken;
  218.           until (FToken = IntegerToken) or (FToken = FloatToken) or (Length(FTokenString) = 1);
  219.           Stream.Seek(FPosition + Length(FTokenString), 0);
  220.         end;
  221.       else
  222.         begin
  223.           FToken:=AChar;
  224.           FTokenString:=AChar;
  225.         end;
  226.       end;
  227.     end;
  228.   end;
  229.   Result:=FToken;
  230. end;
  231.  
  232. function TCustomScanner.GetTokenFloat: extended;
  233. begin
  234.   Result:=StrToFloat(FTokenString);
  235. end;
  236.  
  237. function TCustomScanner.GetTokenInt: longint;
  238. begin
  239.   Result:=StrToInt(FTokenString);
  240. end;
  241.  
  242. function TCustomScanner.LastToken: char;
  243. var
  244.   NewPosition, LastPosition, LastLine: longint;
  245.   AChar: char;
  246. begin
  247.   if FPosition = 0 then
  248.   begin
  249.     Result:=FToken;
  250.     exit;
  251.   end;
  252.   LastPosition:=FPosition;
  253.   NewPosition:=FPosition;
  254.   LastLine:=FLine - 1;
  255.   repeat
  256.     Line:=LastLine;
  257.     Dec(LastLine);
  258.     while FPosition < LastPosition do
  259.     begin
  260.       NewPosition:=FPosition;
  261.       NextToken;
  262.     end;
  263.   until (FPosition = LastPosition) and (NewPosition < LastPosition);
  264.   repeat
  265.     FStream.Seek(-1, 1);
  266.     FStream.Read(AChar, 1);
  267.     FStream.Seek(-1, 1);
  268.     if AChar = NewLineDelimiter then
  269.       Dec(FLine);
  270.   until FStream.Position = NewPosition;
  271.   Result:=NextToken;
  272. end;
  273.  
  274. function TCustomScanner.LineString: string;
  275. var
  276.   OldStream, OldPosition: longint;
  277.   OldToken: char;
  278.   OldString: string;
  279.   Buffer: array[0..255] of char;
  280.   APChar: PChar;
  281. begin
  282.   OldStream:=Stream.Position;
  283.   OldPosition:=FPosition;
  284.   OldToken:=FToken;
  285.   OldString:=FTokenString;
  286.   Line:=FLine;
  287.   Stream.Seek(FPosition, 0);
  288.   Buffer[Stream.Read(Buffer, 255)]:=#0;
  289.   APChar:=StrScan(@Buffer, NewLineDelimiter);
  290.   if APChar <> nil then
  291.     {assumes LF -> CR/LF}
  292.     if ((APChar - 1)^ = #13) and (NewLineDelimiter = #10) then
  293.       (APChar - 1)^:=#0
  294.     else
  295.       APChar^:=#0;
  296.   Result:=StrPas(@Buffer);
  297.   Stream.Seek(OldStream, 0);
  298.   FPosition:=OldPosition;
  299.   FToken:=OldToken;
  300.   FTokenString:=OldString;
  301. end;
  302.  
  303. {
  304.   TFileScanner *************************************************
  305. }
  306. constructor TFileScanner.Create(AFileName: string);
  307. begin
  308.   inherited Create;
  309.   if not FileExists(AFileName) then
  310.     Exit;
  311.   Stream:=TFileStream.Create(AFileName, fmOpenRead);
  312.   FFileName:=AFileName;
  313.   Stream.Seek(0,0);
  314.   NextToken;
  315. end;
  316.  
  317. destructor TFileScanner.Destroy;
  318. begin
  319.   Stream.Free;
  320.   inherited Destroy;
  321. end;
  322.  
  323. {
  324.   TStreamScanner ***********************************************
  325. }
  326. constructor TStreamScanner.Create(AStream: TStream);
  327. begin
  328.   Stream:=AStream;
  329.   Stream.Seek(0,0);
  330.   NextToken;
  331. end;
  332.  
  333. end.
  334.